package com.frejoys.common.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.frejoys.common.aop.Authorization;
import com.frejoys.common.config.ValueConfig;
import com.frejoys.common.constant.CommonConstant;
import com.frejoys.common.enums.ESite;
import com.frejoys.common.enums.ESiteType;
import com.frejoys.common.error.HttpStatus;
import com.frejoys.common.exception.GeneralException;
import com.frejoys.common.request.ThreadContext;
import com.frejoys.common.util.CacheKeyUtil;
import com.frejoys.common.util.JwtUtil;
import com.frejoys.common.util.RedisUtil;
import com.frejoys.common.util.RequestUtil;
import com.frejoys.common.util.TimeUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 权限拦截器
 */
@Component
@RequiredArgsConstructor
public class AuthorityInterceptor implements HandlerInterceptor {

    private final ValueConfig valueConfig;

    private final RedisUtil redisUtil;

    // 执行前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // return HandlerInterceptor.super.preHandle(request, response, handler);
        // System.out.println("AuthorityInterceptor: 开始");

        if (handler instanceof HandlerMethod) {

            Authorization authorization = getMethodAuthorization((HandlerMethod) handler);
            if (authorization == null) {
                return true;
            }

            ThreadContext.get().setAuthority(authorization.value());

            switch (authorization.value()) {
                case Private:

                    /// app
                    if (request.getRequestURI().startsWith(CommonConstant.routePrefixApp)) {
                        this.roleSiteType();

                        ThreadContext.get().setSite(ESite.app.getValue());

                        // 验证签名
                        verifySign(request, valueConfig.getAppHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        // 验证token
                        verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getAppJwtSecret(), ESite.app.getValue(), RequestUtil.siteType());

                    } else if (request.getRequestURI().startsWith(CommonConstant.routePrefixStore)) {
                        this.roleSiteType();

                        ThreadContext.get().setSite(ESite.store.getValue());

                        /// 商家

                        // 验证签名
                        verifySign(request, valueConfig.getStoreHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        // 验证token
                        verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getStoreJwtSecret(), ESite.store.getValue(), RequestUtil.siteType());

                    } else if (request.getRequestURI().startsWith(CommonConstant.routePrefixAdmin)) {
                        this.roleSiteType();

                        ThreadContext.get().setSite(ESite.admin.getValue());
                        /// 后台

                        // 验证签名
                        verifySign(request, valueConfig.getAdminHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        // 验证token
                        verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getAdminJwtSecret(), ESite.admin.getValue(), RequestUtil.siteType());


                    } else {
                        throw new GeneralException(HttpStatus.routeFail);
                    }

                    break;

                case Protected:

                    /// app
                    if (request.getRequestURI().startsWith(CommonConstant.routePrefixApp)) {
                        ThreadContext.get().setSite(ESite.app.getValue());

                        // 验证签名
                        verifySign(request, valueConfig.getAppHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        if (StrUtil.isNotEmpty(request.getHeader(CommonConstant.authorization))) {
                            this.roleSiteType();

                            // 验证token
                            verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getAppJwtSecret(), ESite.app.getValue(), RequestUtil.siteType());
                        }

                    } else if (request.getRequestURI().startsWith(CommonConstant.routePrefixStore)) {
                        ThreadContext.get().setSite(ESite.store.getValue());

                        /// 商家

                        // 验证签名
                        verifySign(request, valueConfig.getStoreHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        if (StrUtil.isNotEmpty(request.getHeader(CommonConstant.authorization))) {
                            this.roleSiteType();

                            // 验证token
                            verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getStoreJwtSecret(), ESite.store.getValue(), RequestUtil.siteType());
                        }

                    } else if (request.getRequestURI().startsWith(CommonConstant.routePrefixAdmin)) {
                        ThreadContext.get().setSite(ESite.admin.getValue());

                        /// 后台

                        // 验证签名
                        verifySign(request, valueConfig.getAdminHeaderSecret(), RequestUtil.site(), RequestUtil.siteType());

                        if (StrUtil.isNotEmpty(request.getHeader(CommonConstant.authorization))) {
                            this.roleSiteType();

                            // 验证token
                            verifyToken(request.getHeader(CommonConstant.authorization), valueConfig.getAdminJwtSecret(), ESite.admin.getValue(), RequestUtil.siteType());
                        }

                    } else {
                        throw new GeneralException(HttpStatus.routeFail);
                    }
                    // verifySign(request, AppConfigUtil.getHeaderSecret(request.getRequestURI()));
                    break;
                case Open:
                    // 验证签名
                    verifySign(request, valueConfig.getAppOpenHeaderSecret(), 0, 0);
                    break;
                case Internal:
                    // ip限制
                    throw new GeneralException(HttpStatus.routeFail);
                    // break;
                case Public:
                    // ThreadContext.get().setSite(ESite.admin.getValue());
                    // ThreadContext.get().setUserId(749771216261120L);
                    break;
                default:
                    return false;
            }

        }

        return true;
    }

    // 结束后
    // @Override
    // public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    //     // HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    // }

    // 获取注解类型
    public Authorization getMethodAuthorization(HandlerMethod method){
        Authorization authorization = null;
        if((authorization = method.getMethodAnnotation(Authorization.class)) != null){
            return authorization;
        }

        if((authorization = method.getMethod().getDeclaringClass().getAnnotation(Authorization.class)) != null){
            return authorization;
        }

        return authorization;
    }

    // 验证签名
    public void verifySign(HttpServletRequest request, String secret, Integer site, Integer siteType) {
        // 获取请求头
        String appid = request.getHeader(CommonConstant.appid);
        String timestamp = request.getHeader(CommonConstant.timestamp);
        String nonce = request.getHeader(CommonConstant.nonce);
        String version = request.getHeader(CommonConstant.version);
        String sign = request.getHeader(CommonConstant.sign);
        if (StrUtil.isEmpty(timestamp) || StrUtil.isEmpty(appid) || StrUtil.isEmpty(nonce) || StrUtil.isEmpty(version) || StrUtil.isEmpty(sign)) {
            throw new GeneralException(HttpStatus.headParmError);
        }

        String key = CacheKeyUtil.signCacheKey(sign + site + siteType);
        if (redisUtil.hasKey(key)) {
            throw new GeneralException(HttpStatus.headSignCacheExist);
        }

        // 请求时长
        Integer nt = TimeUtil.unixTime() - Integer.valueOf(timestamp);
        if (nt < -60 || nt > 60) {
            throw new GeneralException(HttpStatus.headTimeout);
        }

        redisUtil.set(key, 1, 60L);

        String data = "";

        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(request.getInputStream(), request.getCharacterEncoding()));

            StringBuffer sb = new StringBuffer();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

            data = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        String reqSign = DigestUtil.sha1Hex(appid + timestamp + nonce + version + data + secret);

        if (!sign.equals(reqSign)) {
            throw new GeneralException(HttpStatus.headSignFailure);
        }
    }

    // 验证token
    public void verifyToken(String token, String secret, Integer site, Integer siteType) {
        if (StrUtil.isEmpty(token) || "null".equals(token)) {
            throw new GeneralException(HttpStatus.tokenNoExist);
        }

        token = StrUtil.removePrefix(token, "Bearer ");

        // 验证token
        String userId = JwtUtil.verify(token, secret, CommonConstant.userId);

        // 获取缓存中保存的数据对比，如果不存在或者对比不成功，说明新登录的token已经覆盖旧token
        String tokMD5 = (String) redisUtil.get(CacheKeyUtil.singleSignCacheKey(userId, site, siteType));

        if (StrUtil.isEmpty(tokMD5)) {
            throw new GeneralException(HttpStatus.tokenNoFind);
        }

        if (!tokMD5.equals(SecureUtil.md5(token))) {
            throw new GeneralException(HttpStatus.tokenDiff);
        }

        ThreadContext.get().setUserId(Long.valueOf(userId));
    }


    // 限制来源
    public void roleSiteType() {
        // 限制错误来源
        if (!ESiteType.getValues().contains(RequestUtil.siteType())) {
            throw new GeneralException(HttpStatus.siteTypeError);
        }
    }

}
